import pytest
from pytest import MonkeyPatch
import json
from unittest.mock import patch, Mock, mock_open
from motor.config.coordinator import CoordinatorConfig
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 完整的配置模板
COMPLETE_CONFIG = {
    "http_config": {
        "predict_ip": "127.0.0.1",
        "predict_port": "8080",
        "manage_ip": "127.0.0.1",
        "manage_port": "8081",
        "alarm_port": "8082",
        "server_thread_num": 4,
        "client_thread_num": 2,
        "http_timeout_seconds": 10,
        "keep_alive_seconds": 180,
        "server_name": "test_server",
        "user_agent": "test_agent",
        "allow_all_zero_ip_listening": True
    },
    "metrics_config": {
        "enable": True,
        "trigger_size": 100
    },
    "prometheus_metrics_config": {
        "reuse_time": 3
    },
    "exception_config": {
        "max_retry": 5,
        "schedule_timeout": 60,
        "first_token_timeout": 60,
        "infer_timeout": 300,
        "tokenizer_timeout": 300
    },
    "request_limit": {
        "single_node_max_requests": 1000,
        "max_requests": 10000,
        "body_limit": 10485760
    },
    "tls_config": {
        "controller_server_tls_enable": True,
        "controller_server_tls_items": {
            "ca_cert": "ca.pem",
            "tls_cert": "server.pem",
            "tls_key": "server.key",
            "tls_passwd": "password",
            "tls_crl": "crl.pem",
            "kmcKsfMaster": "master_key",
            "kmcKsfStandby": "standby_key"
        }
    },
    "digs_scheduler_config": {
        "deploy_mode": "single_node",
        "scheduler_type": "digs_scheduler",
        "algorithm_type": "load_balance"
    },
    "string_token_rate": 4.2
}

def load_config(config: dict) -> CoordinatorConfig:
    """加载并验证配置"""
    with patch('builtins.open', mock_open(read_data=json.dumps(config))):
        coordinator = CoordinatorConfig()
        result = coordinator.init()
        assert result == 0, "Failed to initialize configuration"
        return coordinator

def load_invalid_config(config: dict) -> int:
    with patch('builtins.open', mock_open(read_data=json.dumps(config))):
        coordinator = CoordinatorConfig()
        result = coordinator.init()
        # 清理步骤：重置配置
        config.__init__()
        return result

class TestCoordinatorConfig:
    @pytest.mark.asyncio
    async def test_init_success(self, monkeypatch: MonkeyPatch):
        """测试初始化成功"""
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.http_config.predict_ip == "127.0.0.1"
        assert coordinator.http_config.predict_port == "8080"
        assert coordinator.metrics_config.enable is True
        assert coordinator.metrics_config.trigger_size == 100
        assert coordinator.prometheus_metrics_config.reuse_time == 3
        assert coordinator.exception_config.max_retry == 5
        assert coordinator.req_limit.single_node_max_reqs == 1000
        assert coordinator.req_limit.max_reqs == 10000
        assert coordinator.req_limit.body_limit == 10485760
        assert coordinator.controller_server_tls.tls_enable is True
        assert coordinator.controller_server_tls.items == config["tls_config"]["controller_server_tls_items"]
        assert coordinator.scheduler_config == config["digs_scheduler_config"]
        assert coordinator.str_token_rate == 4.2

    @pytest.mark.asyncio
    async def test_init_failure(self, monkeypatch: MonkeyPatch):
        """测试初始化失败"""
        with patch('builtins.open', Mock(side_effect=FileNotFoundError())):
            config = CoordinatorConfig()
            result = config.init()
            assert result == -1

    @pytest.mark.asyncio
    async def test_http_config(self, monkeypatch: MonkeyPatch):
        """测试HTTP配置"""
        config = COMPLETE_CONFIG.copy()
        config["http_config"]["predict_port"] = "8080"
        coordinator = load_config(config)
        
        assert coordinator.http_config.predict_ip == "127.0.0.1"
        assert coordinator.http_config.predict_port == "8080"
        assert coordinator.http_config.manage_ip == "127.0.0.1"
        assert coordinator.http_config.manage_port == "8081"
        assert coordinator.http_config.alarm_port == "8082"
        assert coordinator.http_config.server_thread_num == 4
        assert coordinator.http_config.client_thread_num == 2
        assert coordinator.http_config.http_timeout_seconds == 10
        assert coordinator.http_config.keep_alive_seconds == 180
        assert coordinator.http_config.server_name == "test_server"
        assert coordinator.http_config.user_agent == "test_agent"
        assert coordinator.http_config.allow_all_zero_ip_listening is True

    @pytest.mark.asyncio
    async def test_metrics_config(self, monkeypatch: MonkeyPatch):
        """测试Metrics配置"""
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.metrics_config.enable is True
        assert coordinator.metrics_config.trigger_size == 100
        assert coordinator.prometheus_metrics_config.reuse_time == 3

    @pytest.mark.asyncio
    async def test_exception_config(self, monkeypatch: MonkeyPatch):
        """测试异常配置"""
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.exception_config.max_retry == 5
        assert coordinator.exception_config.schedule_timeout == 60
        assert coordinator.exception_config.first_token_timeout == 60
        assert coordinator.exception_config.infer_timeout == 300
        assert coordinator.exception_config.tokenizer_timeout == 300

    @pytest.mark.asyncio
    async def test_request_limit(self, monkeypatch: MonkeyPatch):
        """测试请求限制配置"""
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.req_limit.single_node_max_reqs == 1000
        assert coordinator.req_limit.max_reqs == 10000
        assert coordinator.req_limit.body_limit == 10485760

    @pytest.mark.asyncio
    async def test_tls_config(self, monkeypatch: MonkeyPatch):
        """测试TLS配置"""
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.controller_server_tls.tls_enable is True
        assert coordinator.controller_server_tls.items == config["tls_config"]["controller_server_tls_items"]

    @pytest.mark.asyncio
    async def test_scheduler_config(self, monkeypatch: MonkeyPatch):
        """测试Scheduler配置"""
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.scheduler_config == config["digs_scheduler_config"]

    @pytest.mark.asyncio
    async def test_str_token_rate(self, monkeypatch: MonkeyPatch):
        """测试字符串令牌率配置"""
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.str_token_rate == 4.2


    @pytest.mark.asyncio
    async def test_env_vars_request_limit(self, monkeypatch: MonkeyPatch):
        """测试环境变量请求限制"""
        monkeypatch.setenv("MINDIE_MS_COORDINATOR_CONFIG_SINGLE_NODE_MAX_REQ", "2000")
        monkeypatch.setenv("MINDIE_MS_COORDINATOR_CONFIG_MAX_REQ", "20000")
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.req_limit.single_node_max_reqs == 2000
        assert coordinator.req_limit.max_reqs == 20000
        assert coordinator.req_limit.body_limit == 10485760

    @pytest.mark.asyncio
    async def test_invalid_env_vars_request_limit(self, monkeypatch: MonkeyPatch):
        """测试无效的环境变量请求限制"""
        monkeypatch.setenv("MINDIE_MS_COORDINATOR_CONFIG_SINGLE_NODE_MAX_REQ", "invalid")
        monkeypatch.setenv("MINDIE_MS_COORDINATOR_CONFIG_MAX_REQ", "invalid")
        config = COMPLETE_CONFIG.copy()
        coordinator = load_config(config)
        
        assert coordinator.req_limit.single_node_max_reqs == 1000
        assert coordinator.req_limit.max_reqs == 10000
        assert coordinator.req_limit.body_limit == 10485760

        # 清理步骤：重置配置
        coordinator.__init__()

    @pytest.mark.asyncio
    async def test_invalid_deploy_mode(self, monkeypatch: MonkeyPatch):
        """测试无效的部署模式"""
        config = COMPLETE_CONFIG.copy()
        config["digs_scheduler_config"]["deploy_mode"] = "invalid_mode"
        result = load_invalid_config(config)
        assert result == -1

    @pytest.mark.asyncio
    async def test_invalid_scheduler_type(self, monkeypatch: MonkeyPatch):
        """测试无效的调度器类型"""
        config = COMPLETE_CONFIG.copy()
        config["digs_scheduler_config"]["scheduler_type"] = "invalid_scheduler"
        result = load_invalid_config(config)
        assert result == -1

    @pytest.mark.asyncio
    async def test_invalid_algorithm_type(self, monkeypatch: MonkeyPatch):
        """测试无效的算法类型"""
        config = COMPLETE_CONFIG.copy()
        config["digs_scheduler_config"]["algorithm_type"] = "invalid_algorithm"
        result = load_invalid_config(config)
        assert result == -1

    @pytest.mark.asyncio
    async def test_missing_required_fields(self, monkeypatch: MonkeyPatch):
        """测试缺失必填字段"""
        config = COMPLETE_CONFIG.copy()
        config["digs_scheduler_config"] = {
                "deploy_mode": "single_node",
                "scheduler_type": "digs_scheduler"
            }
        result = load_invalid_config(config)
        assert result == -1

